"""
GT-LMS System User Model
This module defines user-related classes, including base class User and its subclasses Student, Teacher, Admin
"""

from abc import ABC, abstractmethod
from datetime import datetime
from typing import Dict, List, Optional, Any
from enum import Enum


class UserRole(Enum):
    """User role enumeration"""
    STUDENT = "student"
    TEACHER = "teacher"
    ADMIN = "admin"


class User(ABC):
    """User base class - implements inheritance and encapsulation"""
    
    def __init__(self, user_id: str, name: str, email: str, password: str, role: UserRole):
        """
        Initialize user
        
        Parameters:
            user_id: User ID
            name: Name
            email: Email
            password: Password
            role: User role
        """
        self.user_id = user_id
        self.name = name
        self.email = email
        self._password = password  # Private attribute, encapsulation
        self.role = role
        self.created_at = datetime.now()
        self.last_login = datetime.now()
        self.is_active = True
    
    def verify_password(self, password: str) -> bool:
        """Verify password"""
        return self._password == password
    
    def change_password(self, old_pwd: str, new_pwd: str) -> bool:
        """Change password"""
        if self.verify_password(old_pwd):
            self._password = new_pwd
            return True
        return False
    
    def update_profile(self, info: Dict[str, Any]) -> bool:
        """Update user information"""
        if 'name' in info:
            self.name = info['name']
        if 'email' in info:
            self.email = info['email']
        return True
    
    def get_info(self) -> Dict[str, Any]:
        """Get user information"""
        return {
            'user_id': self.user_id,
            'name': self.name,
            'email': self.email,
            'role': self.role.value,
            'created_at': self.created_at.isoformat(),
            'last_login': self.last_login.isoformat(),
            'is_active': self.is_active
        }
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary format - compatible with serialization"""
        return self.get_info()
    
    def deactivate(self) -> None:
        """Deactivate account"""
        self.is_active = False
    
    def activate(self) -> None:
        """Activate account"""
        self.is_active = True
    
    def update_last_login(self) -> None:
        """Update last login time"""
        self.last_login = datetime.now()
    
    @abstractmethod
    def view_dashboard(self) -> None:
        """View dashboard - abstract method, subclasses must implement"""
        pass
    
    @abstractmethod
    def get_permissions(self) -> List[str]:
        """Get permission list - abstract method, subclasses must implement"""
        pass
    
    def get_role(self) -> str:
        """Get user role"""
        return self.role.value
    
    def get_name(self) -> str:
        """Get user name"""  
        return self.name
    
    def get_email(self) -> str:
        """Get user email"""
        return self.email


class Student(User):
    """Student class"""
    
    def __init__(self, user_id: str, name: str, email: str, password: str, 
                 student_number: str, major: str = "", enrollment_year: int = None):
        """
        Initialize student
        
        Parameters:
            user_id: User ID
            name: Name
            email: Email
            password: Password
            student_number: Student number
            major: Major
            enrollment_year: Enrollment year
        """
        super().__init__(user_id, name, email, password, UserRole.STUDENT)
        self.student_number = student_number
        self.major = major
        self.enrollment_year = enrollment_year or datetime.now().year
        self.enrolled_courses: List[str] = []  # List of enrolled course IDs
        self.gpa: float = 0.0
        self.grades: Dict[str, float] = {}  # Course ID -> Grade
    
    def view_dashboard(self) -> None:
        """Student view dashboard"""
        print(f"\n=== Student Dashboard ===")
        print(f"Name: {self.name}")
        print(f"Student Number: {self.student_number}")
        print(f"Major: {self.major}")
        print(f"GPA: {self.gpa:.2f}")
        print(f"Enrolled Courses: {len(self.enrolled_courses)}")
        print(f"Last Login: {self.last_login.strftime('%Y-%m-%d %H:%M')}")
    
    def get_permissions(self) -> List[str]:
        """Get student permissions"""
        return [
            "view_courses",
            "enroll_course", 
            "drop_course",
            "view_grades",
            "view_progress",
            "submit_assignment",
            "view_assignments"
        ]
    
    def enroll_course(self, course_id: str) -> bool:
        """Enroll in course"""
        if course_id not in self.enrolled_courses:
            self.enrolled_courses.append(course_id)
            return True
        return False
    
    def drop_course(self, course_id: str) -> bool:
        """Drop course"""
        if course_id in self.enrolled_courses:
            self.enrolled_courses.remove(course_id)
            return True
        return False
    
    def view_courses(self) -> List[str]:
        """View enrolled courses"""
        return self.enrolled_courses.copy()
    
    def view_grades(self) -> Dict[str, float]:
        """View grades"""
        return self.grades.copy()
    
    def add_grade(self, course_id: str, grade: float) -> None:
        """Add grade"""
        self.grades[course_id] = grade
        self.calculate_gpa()
    
    def calculate_gpa(self) -> float:
        """Calculate GPA"""
        if not self.grades:
            self.gpa = 0.0
        else:
            total_grade = sum(self.grades.values())
            self.gpa = total_grade / len(self.grades)
        return self.gpa
    
    def get_enrolled_courses(self) -> List[str]:
        """Get enrolled courses"""
        return self.enrolled_courses.copy()
    
    def get_grades(self) -> Dict[str, float]:
        """Get grades"""
        return self.grades.copy()
    
    def get_id(self) -> str:
        """Get user ID"""
        return self.user_id


class Teacher(User):
    """Teacher class"""
    
    def __init__(self, user_id: str, name: str, email: str, password: str, 
                 employee_id: str, department: str = "", office_hours: str = ""):
        """
        Initialize teacher
        
        Parameters:
            user_id: User ID
            name: Name
            email: Email
            password: Password
            employee_id: Employee ID
            department: Department
            office_hours: Office hours
        """
        super().__init__(user_id, name, email, password, UserRole.TEACHER)
        self.employee_id = employee_id
        self.department = department
        self.office_hours = office_hours
        self.teaching_courses: List[str] = []  # List of taught course IDs
    
    def view_dashboard(self) -> None:
        """Teacher view dashboard"""
        print(f"\n=== Teacher Dashboard ===")
        print(f"Name: {self.name}")
        print(f"Employee ID: {self.employee_id}")
        print(f"Department: {self.department}")
        print(f"Teaching Courses: {len(self.teaching_courses)}")
        print(f"Office Hours: {self.office_hours}")
        print(f"Last Login: {self.last_login.strftime('%Y-%m-%d %H:%M')}")
    
    def get_permissions(self) -> List[str]:
        """Get teacher permissions"""
        return [
            "view_courses",
            "create_course",
            "update_course", 
            "delete_course",
            "create_assignment",
            "update_assignment",
            "delete_assignment",
            "view_submissions",
            "grade_submission",
            "view_class_roster",
            "view_course_statistics"
        ]
    
    def add_teaching_course(self, course_id: str) -> None:
        """Add teaching course"""
        if course_id not in self.teaching_courses:
            self.teaching_courses.append(course_id)
    
    def remove_teaching_course(self, course_id: str) -> bool:
        """Remove teaching course"""
        if course_id in self.teaching_courses:
            self.teaching_courses.remove(course_id)
            return True
        return False
    
    def get_teaching_courses(self) -> List[str]:
        """Get teaching courses"""
        return self.teaching_courses.copy()
    
    def get_id(self) -> str:
        """Get user ID"""
        return self.user_id


class Admin(User):
    """Admin class"""
    
    def __init__(self, user_id: str, name: str, email: str, password: str, admin_level: int = 1):
        """
        Initialize admin
        
        Parameters:
            user_id: User ID
            name: Name
            email: Email
            password: Password
            admin_level: Admin level
        """
        super().__init__(user_id, name, email, password, UserRole.ADMIN)
        self.admin_level = admin_level
        self.permissions: List[str] = self._get_admin_permissions(admin_level)
    
    def _get_admin_permissions(self, level: int) -> List[str]:
        """Get permissions based on admin level"""
        base_permissions = [
            "view_courses",
            "view_users", 
            "view_system_stats",
            "generate_reports"
        ]
        
        if level >= 3:
            base_permissions.extend([
                "create_user",
                "update_user",
                "delete_user",
                "manage_user_permissions"
            ])
        
        if level >= 5:
            base_permissions.extend([
                "create_course", 
                "update_course",
                "delete_course",
                "manage_course_permissions"
            ])
        
        if level >= 7:
            base_permissions.extend([
                "backup_system",
                "restore_system",
                "system_maintenance",
                "view_system_logs"
            ])
        
        if level >= 10:
            base_permissions.extend([
                "super_admin",
                "manage_all_admins",
                "system_configuration"
            ])
        
        return base_permissions
    
    def view_dashboard(self) -> None:
        """Admin view dashboard"""
        print(f"\n=== Admin Dashboard ===")
        print(f"Name: {self.name}")
        print(f"Admin Level: {self.admin_level}")
        print(f"Permissions Count: {len(self.permissions)}")
        print(f"Last Login: {self.last_login.strftime('%Y-%m-%d %H:%M')}")
    
    def get_permissions(self) -> List[str]:
        """Get admin permissions"""
        return self.permissions.copy()
    
    def get_id(self) -> str:
        """Get user ID"""
        return self.user_id
    
    def update_admin_level(self, new_level: int) -> None:
        """Update admin level"""
        self.admin_level = new_level
        self.permissions = self._get_admin_permissions(new_level)